home *** CD-ROM | disk | FTP | other *** search
/ Aminet 21 / Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso / Aminet / gfx / show / gs_src_gs.lha / gs5.03 / gdevbbox.c < prev    next >
C/C++ Source or Header  |  1997-07-03  |  24KB  |  750 lines

  1. /* Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevbbox.c */
  20. /* Device for tracking bounding box */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gsparam.h"
  26. #include "gxdevice.h"
  27. #include "gsdevice.h"        /* requires gsmatrix.h */
  28. #include "gdevbbox.h"
  29. #include "gxistate.h"
  30. #include "gxpaint.h"
  31. #include "gxpath.h"
  32. #include "gxcpath.h"
  33.  
  34. /* Define TEST to create an output_page procedure for testing. */
  35. /*#define TEST*/
  36.  
  37. /* GC descriptor */
  38. public_st_device_bbox();
  39.  
  40. /* Device procedures */
  41. private dev_proc_open_device(bbox_open_device);
  42. private dev_proc_close_device(gx_forward_close_device);    /* see below */
  43. private dev_proc_output_page(bbox_output_page);
  44. private dev_proc_fill_rectangle(bbox_fill_rectangle);
  45. private dev_proc_copy_mono(bbox_copy_mono);
  46. private dev_proc_copy_color(bbox_copy_color);
  47. private dev_proc_draw_line(bbox_draw_line);
  48. private dev_proc_get_params(bbox_get_params);
  49. private dev_proc_put_params(bbox_put_params);
  50. private dev_proc_copy_alpha(bbox_copy_alpha);
  51. private dev_proc_fill_path(bbox_fill_path);
  52. private dev_proc_stroke_path(bbox_stroke_path);
  53. private dev_proc_fill_mask(bbox_fill_mask);
  54. private dev_proc_fill_trapezoid(bbox_fill_trapezoid);
  55. private dev_proc_fill_parallelogram(bbox_fill_parallelogram);
  56. private dev_proc_fill_triangle(bbox_fill_triangle);
  57. private dev_proc_draw_thin_line(bbox_draw_thin_line);
  58. private dev_proc_begin_image(bbox_begin_image);
  59. private dev_proc_image_data(bbox_image_data);
  60. private dev_proc_end_image(bbox_end_image);
  61. private dev_proc_strip_tile_rectangle(bbox_strip_tile_rectangle);
  62. private dev_proc_strip_copy_rop(bbox_strip_copy_rop);
  63.  
  64. /* The device prototype */
  65. #ifndef TEST
  66. private const
  67. #endif
  68. /* We initialize with a very high resolution, to prevent limitchecks */
  69. /* if the resolution is changed to any reasonable value. */
  70. /* We initialize the width and height to "infinite" values, */
  71. /* leaving a little room for stroke widths, rounding, etc. */
  72. #define max_coord (min(max_int, fixed2int(max_fixed)) - 1000)
  73. #define max_resolution 4000
  74. gx_device_bbox far_data gs_bbox_device = {
  75.     std_device_std_body(gx_device_bbox, 0, "bbox",
  76.                 max_coord, max_coord,
  77.                 max_resolution, max_resolution),
  78.     {    bbox_open_device,
  79.         NULL,            /* get_initial_matrix */
  80.         NULL,            /* sync_output */
  81.         bbox_output_page,
  82.         gx_forward_close_device,
  83.         NULL,            /* map_rgb_color */
  84.         NULL,            /* map_color_rgb */
  85.         bbox_fill_rectangle,
  86.         NULL,            /* tile_rectangle */
  87.         bbox_copy_mono,
  88.         bbox_copy_color,
  89.         bbox_draw_line,
  90.         NULL,            /* get_bits */
  91.         bbox_get_params,
  92.         bbox_put_params,
  93.         NULL,            /* map_cmyk_color */
  94.         NULL,            /* get_xfont_procs */
  95.         NULL,            /* get_xfont_device */
  96.         NULL,            /* map_rgb_alpha_color */
  97.         gx_page_device_get_page_device,
  98.         NULL,            /* get_alpha_bits */
  99.         bbox_copy_alpha,
  100.         NULL,            /* get_band */
  101.         NULL,            /* copy_rop */
  102.         bbox_fill_path,
  103.         bbox_stroke_path,
  104.         bbox_fill_mask,
  105.         bbox_fill_trapezoid,
  106.         bbox_fill_parallelogram,
  107.         bbox_fill_triangle,
  108.         bbox_draw_thin_line,
  109.         bbox_begin_image,
  110.         bbox_image_data,
  111.         bbox_end_image,
  112.         bbox_strip_tile_rectangle,
  113.         bbox_strip_copy_rop
  114.     },
  115.     0                /* target */
  116. };
  117. #undef max_coord
  118. #undef max_resolution
  119.  
  120. /* Copy device parameters back from the target. */
  121. private void
  122. bbox_copy_params(gx_device_bbox *bdev)
  123. {    gx_device *tdev = bdev->target;
  124.     if ( tdev != 0 )
  125.       { /* This is kind of scatter-shot.... */
  126. #define copy_param(p) bdev->p = tdev->p
  127. #define copy_array_param(p) memcpy(bdev->p, tdev->p, sizeof(bdev->p))
  128.         copy_param(width);
  129.         copy_param(height);
  130.         copy_array_param(MediaSize);
  131.         copy_array_param(ImagingBBox);
  132.         copy_param(ImagingBBox_set);
  133.         copy_array_param(HWResolution);
  134.         copy_array_param(MarginsHWResolution);
  135.         copy_array_param(Margins);
  136.         copy_array_param(HWMargins);
  137.         copy_param(color_info);
  138. #undef copy_param
  139. #undef copy_array_param
  140.       }
  141.     if ( dev_proc(bdev, map_rgb_color) != 0 )
  142.       bdev->white =
  143.         (*dev_proc(bdev, map_rgb_color))
  144.           ((gx_device *)bdev, gx_max_color_value, gx_max_color_value,
  145.            gx_max_color_value);
  146. }
  147.  
  148. #define bdev ((gx_device_bbox *)dev)
  149.  
  150. #define gx_dc_is_white(pdevc, bdev)\
  151.   (gx_dc_is_pure(pdevc) && gx_dc_pure_color(pdevc) == (bdev)->white)
  152.  
  153. /* Note that some of the "forward" procedures don't exist. */
  154. /* We open-code all but this one below. */
  155. private int
  156. gx_forward_close_device(gx_device *dev)
  157. {    gx_device *tdev = bdev->target;
  158.     return (tdev == 0 ? 0 : (*dev_proc(tdev, close_device))(tdev));
  159. }
  160.  
  161. /* Bounding box utilities */
  162.  
  163. private void near
  164. bbox_initialize(gs_fixed_rect *pr)
  165. {    pr->p.x = pr->p.y = max_fixed;
  166.     pr->q.x = pr->q.y = min_fixed;
  167. }
  168.  
  169. private void near
  170. bbox_add_rect(gs_fixed_rect *pr, fixed x0, fixed y0, fixed x1, fixed y1)
  171. {    if ( x0 < pr->p.x )
  172.       pr->p.x = x0;
  173.     if ( y0 < pr->p.y )
  174.       pr->p.y = y0;
  175.     if ( x1 > pr->q.x )
  176.       pr->q.x = x1;
  177.     if ( y1 > pr->q.y )
  178.       pr->q.y = y1;
  179. }
  180. private void near
  181. bbox_add_point(gs_fixed_rect *pr, fixed x, fixed y)
  182. {    bbox_add_rect(pr, x, y, x, y);
  183. }
  184. private void near
  185. bbox_add_int_rect(gs_fixed_rect *pr, int x0, int y0, int x1, int y1)
  186. {    bbox_add_rect(pr, int2fixed(x0), int2fixed(y0), int2fixed(x1),
  187.               int2fixed(y1));
  188. }
  189.  
  190. #define rect_is_page(dev, x, y, w, h)\
  191.   (x <= 0 && y <= 0 && w >= x + dev->width && h >= y + dev->height)
  192.  
  193. /* ---------------- Open/close/page ---------------- */
  194.  
  195. /* Initialize a bounding box device. */
  196. void
  197. gx_device_bbox_init(gx_device_bbox *dev, gx_device *target)
  198. {    *dev = gs_bbox_device;
  199.     gx_device_forward_fill_in_procs((gx_device_forward *)dev);
  200.     bdev->target = target;
  201.     bbox_copy_params(dev);
  202. }
  203.  
  204. /* Read back the bounding box in 1/72" units. */
  205. void
  206. gx_device_bbox_bbox(gx_device_bbox *dev, gs_rect *pbbox)
  207. {    gs_matrix mat;
  208.     gs_rect dbox;
  209.  
  210.     gs_deviceinitialmatrix((gx_device *)dev, &mat);
  211.     dbox.p.x = fixed2float(bdev->bbox.p.x);
  212.     dbox.p.y = fixed2float(bdev->bbox.p.y);
  213.     dbox.q.x = fixed2float(bdev->bbox.q.x);
  214.     dbox.q.y = fixed2float(bdev->bbox.q.y);
  215.     gs_bbox_transform_inverse(&dbox, &mat, pbbox);
  216. }
  217.  
  218.  
  219. private int
  220. bbox_open_device(gx_device *dev)
  221. {    bbox_initialize(&bdev->bbox);
  222. #ifdef TEST
  223.     gx_device_forward_fill_in_procs((gx_device_forward *)dev);
  224. #endif
  225.     /* gx_forward_open_device doesn't exist */
  226.     { gx_device *tdev = bdev->target;
  227.       int code = (tdev == 0 ? 0 : (*dev_proc(tdev, open_device))(tdev));
  228.       bbox_copy_params(bdev);
  229.       return code;
  230.     }
  231. }
  232.  
  233. private int 
  234. bbox_output_page(gx_device *dev, int num_copies, int flush)
  235. {
  236. #ifdef TEST
  237.     gs_rect bbox;
  238.  
  239.     /* Print the page bounding box. */
  240.     gx_device_bbox_bbox((gx_device_bbox *)dev, &bbox);
  241.     dprintf2("[gdevbbox] lower left  = %f %f\n", bbox.p.x, bbox.p.y);
  242.     dprintf2("[gdevbbox] upper right = %f %f\n", bbox.q.x, bbox.q.y);
  243. #endif
  244.     /* Propagate the PageCount to the target, */
  245.     /* since it changes every time gs_output_page is called. */
  246.     if ( bdev->target )
  247.       bdev->target->PageCount = dev->PageCount;
  248.     return gx_forward_output_page(dev, num_copies, flush);
  249. }
  250.  
  251. /* ---------------- Low-level drawing ---------------- */
  252.  
  253. private int
  254. bbox_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  255.   gx_color_index color)
  256. {    /* Check for erasing the entire page. */
  257.     if ( rect_is_page(dev, x, y, w, h) )
  258.       bbox_initialize(&bdev->bbox);
  259.     else if ( color != bdev->white )
  260.       bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  261.     /* gx_forward_fill_rectangle doesn't exist */
  262.     { gx_device *tdev = bdev->target;
  263.       return (tdev == 0 ? 0 :
  264.           (*dev_proc(tdev, fill_rectangle))(tdev, x, y, w, h, color));
  265.     }
  266. }
  267.  
  268. private int
  269. bbox_copy_mono(gx_device *dev, const byte *data,
  270.   int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
  271.   gx_color_index zero, gx_color_index one)
  272. {    if ( (one != gx_no_color_index && one != bdev->white) ||
  273.          (zero != gx_no_color_index && zero != bdev->white)
  274.        )
  275.       bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  276.     /* gx_forward_copy_mono doesn't exist */
  277.     { gx_device *tdev = bdev->target;
  278.       return (tdev == 0 ? 0 :
  279.           (*dev_proc(tdev, copy_mono))(tdev, data, dx, raster, id,
  280.                            x, y, w, h, zero, one));
  281.     }
  282. }
  283.  
  284. private int
  285. bbox_copy_color(gx_device *dev, const byte *data,
  286.   int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h)
  287. {    bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  288.     /* gx_forward_copy_color doesn't exist */
  289.     { gx_device *tdev = bdev->target;
  290.       return (tdev == 0 ? 0 :
  291.           (*dev_proc(tdev, copy_color))(tdev, data, dx, raster, id,
  292.                            x, y, w, h));
  293.     }
  294. }
  295.  
  296. private int
  297. bbox_draw_line(gx_device *dev,
  298.   int x0, int y0, int x1, int y1, gx_color_index color)
  299. {    int xp, yp, xq, yq;
  300.     if ( x0 < x1 )
  301.       xp = x0, xq = x1 + 1;
  302.     else
  303.       xp = x1, xq = x0 + 1;
  304.     if ( y0 < y1 )
  305.       yp = y0, yq = y1 + 1;
  306.     else
  307.       yp = y1, yq = y0 + 1;
  308.     if ( color != bdev->white )
  309.       bbox_add_int_rect(&bdev->bbox, xp, yp, xq, yq);
  310.     /* gx_forward_draw_line doesn't exist */
  311.     { gx_device *tdev = bdev->target;
  312.       return (tdev == 0 ? 0 :
  313.           (*dev_proc(tdev, draw_line))(tdev, x0, y0, x1, y1, color));
  314.     }
  315. }
  316.  
  317. private int
  318. bbox_copy_alpha(gx_device *dev, const byte *data, int data_x,
  319.   int raster, gx_bitmap_id id, int x, int y, int w, int h,
  320.   gx_color_index color, int depth)
  321. {    bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  322.     /* gx_forward_copy_alpha doesn't exist */
  323.     { gx_device *tdev = bdev->target;
  324.       return (tdev == 0 ? 0 :
  325.           (*dev_proc(tdev, copy_alpha))(tdev, data, data_x, raster, id,
  326.                         x, y, w, h, color, depth));
  327.     }
  328. }
  329.  
  330. private int
  331. bbox_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles,
  332.   int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
  333.   int px, int py)
  334. {    if ( rect_is_page(dev, x, y, w, h) )
  335.       bbox_initialize(&bdev->bbox);
  336.     else
  337.       bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  338.     /* Skip the call if there is no target. */
  339.     { gx_device *tdev = bdev->target;
  340.       return (tdev == 0 ? 0 :
  341.           (*dev_proc(tdev, strip_tile_rectangle))(tdev, tiles, x, y,
  342.                         w, h, color0, color1, px, py));
  343.     }
  344. }
  345.  
  346. private int
  347. bbox_strip_copy_rop(gx_device *dev,
  348.   const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
  349.   const gx_color_index *scolors,
  350.   const gx_strip_bitmap *textures, const gx_color_index *tcolors,
  351.   int x, int y, int w, int h,
  352.   int phase_x, int phase_y, gs_logical_operation_t lop)
  353. {    bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  354.     /* gx_forward_strip_copy_rop doesn't exist */
  355.     { gx_device *tdev = bdev->target;
  356.       return (tdev == 0 ? 0 :
  357.           (*dev_proc(tdev, strip_copy_rop))(tdev,
  358.                           sdata, sourcex, sraster, id,
  359.                           scolors, textures, tcolors,
  360.                           x, y, w, h,
  361.                           phase_x, phase_y, lop));
  362.     }
  363. }
  364.  
  365. /* ---------------- Parameters ---------------- */
  366.  
  367. /* We implement get_params to provide a way to read out the bounding box. */
  368. private int
  369. bbox_get_params(gx_device *dev, gs_param_list *plist)
  370. {    int code = gx_forward_get_params(dev, plist);
  371.     gs_param_float_array bba;
  372.     float bbox[4];
  373.  
  374.     if ( code < 0 )
  375.       return code;
  376.     bbox[0] = fixed2float(bdev->bbox.p.x);
  377.     bbox[1] = fixed2float(bdev->bbox.p.y);
  378.     bbox[2] = fixed2float(bdev->bbox.q.x);
  379.     bbox[3] = fixed2float(bdev->bbox.q.y);
  380.     bba.data = bbox, bba.size = 4, bba.persistent = false;
  381.     return param_write_float_array(plist, "PageBoundingBox", &bba);
  382. }
  383.  
  384. /* We implement put_params to ensure that we keep the important */
  385. /* device parameters up to date, and to prevent an /undefined error */
  386. /* from PageBoundingBox. */
  387. private int
  388. bbox_put_params(gx_device *dev, gs_param_list *plist)
  389. {    int code;
  390.     int ecode = 0;
  391.     gs_param_name param_name;
  392.     gs_param_float_array bba;
  393.  
  394.     code = param_read_float_array(plist, (param_name = "PageBoundingBox"),
  395.                       &bba);
  396.     switch ( code )
  397.       {
  398.       case 0:
  399.         if ( bba.size != 4 )
  400.           { ecode = gs_note_error(gs_error_rangecheck);
  401.             goto e;
  402.           }
  403.         break;
  404.       default:
  405.         ecode = code;
  406. e:        param_signal_error(plist, param_name, ecode);
  407.       case 1:
  408.         bba.data = 0;
  409.       }
  410.  
  411.     code = gx_forward_put_params(dev, plist);
  412.     if ( ecode < 0 )
  413.       code = ecode;
  414.     if ( code >= 0 && bba.data != 0 )
  415.       { bdev->bbox.p.x = float2fixed(bba.data[0]);
  416.         bdev->bbox.p.y = float2fixed(bba.data[1]);
  417.         bdev->bbox.q.x = float2fixed(bba.data[2]);
  418.         bdev->bbox.q.y = float2fixed(bba.data[3]);
  419.       }
  420.     bbox_copy_params(bdev);
  421.     return code;
  422. }
  423.  
  424. /* ---------------- Polygon drawing ---------------- */
  425.  
  426. private fixed
  427. edge_x_at_y(const gs_fixed_edge *edge, fixed y)
  428. {    return fixed_mult_quo(edge->end.x - edge->start.x,
  429.                   y - edge->start.y,
  430.                   edge->end.y - edge->start.y) + edge->start.x;
  431. }
  432. private int
  433. bbox_fill_trapezoid(gx_device *dev,
  434.   const gs_fixed_edge *left, const gs_fixed_edge *right,
  435.   fixed ybot, fixed ytop, bool swap_axes,
  436.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  437. {    if ( !gx_dc_is_white(pdevc, bdev) )
  438.       { fixed x0l =
  439.           (left->start.y == ybot ? left->start.x :
  440.            edge_x_at_y(left, ybot));
  441.         fixed x1l =
  442.           (left->end.y == ytop ? left->end.x :
  443.            edge_x_at_y(left, ytop));
  444.         fixed x0r =
  445.           (right->start.y == ybot ? right->start.x :
  446.            edge_x_at_y(right, ybot));
  447.         fixed x1r =
  448.           (right->end.y == ytop ? right->end.x :
  449.            edge_x_at_y(right, ytop));
  450.         fixed xminl = min(x0l, x1l), xmaxl = max(x0l, x1l);
  451.         fixed xminr = min(x0r, x1r), xmaxr = max(x0r, x1r);
  452.         fixed x0 = min(xminl, xminr), x1 = max(xmaxl, xmaxr);
  453.  
  454.         if ( swap_axes )
  455.           bbox_add_rect(&bdev->bbox, ybot, x0, ytop, x1);
  456.         else
  457.           bbox_add_rect(&bdev->bbox, x0, ybot, x1, ytop);
  458.       }
  459.     /* Skip the call if there is no target. */
  460.     { gx_device *tdev = bdev->target;
  461.       return (tdev == 0 ? 0 :
  462.           (*dev_proc(tdev, fill_trapezoid))
  463.            (tdev, left, right, ybot, ytop, swap_axes, pdevc, lop));
  464.     }
  465. }
  466.  
  467. private int
  468. bbox_fill_parallelogram(gx_device *dev,
  469.   fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  470.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  471. {    if ( !gx_dc_is_white(pdevc, bdev) )
  472.       { fixed pax = px + ax, pay = py + ay;
  473.         bbox_add_rect(&bdev->bbox, px, py, px + bx, py + by);
  474.         bbox_add_rect(&bdev->bbox, pax, pay, pax + bx, pay + by);
  475.       }
  476.     /* Skip the call if there is no target. */
  477.     { gx_device *tdev = bdev->target;
  478.       return (tdev == 0 ? 0 :
  479.           (*dev_proc(tdev, fill_parallelogram))(tdev, px, py, ax, ay,
  480.                             bx, by, pdevc, lop));
  481.     }
  482. }
  483.  
  484. private int
  485. bbox_fill_triangle(gx_device *dev,
  486.   fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  487.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  488. {    if ( !gx_dc_is_white(pdevc, bdev) )
  489.       { bbox_add_rect(&bdev->bbox, px, py, px + bx, py + by);
  490.         bbox_add_point(&bdev->bbox, px + ax, py + ay);
  491.       }
  492.     /* Skip the call if there is no target. */
  493.     { gx_device *tdev = bdev->target;
  494.       return (tdev == 0 ? 0 :
  495.           (*dev_proc(tdev, fill_triangle))(tdev, px, py, ax, ay,
  496.                            bx, by, pdevc, lop));
  497.     }
  498. }
  499.  
  500. private int
  501. bbox_draw_thin_line(gx_device *dev,
  502.   fixed fx0, fixed fy0, fixed fx1, fixed fy1,
  503.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  504. {    if ( !gx_dc_is_white(pdevc, bdev) )
  505.       bbox_add_rect(&bdev->bbox, fx0, fy0, fx1, fy1);
  506.     /* Skip the call if there is no target. */
  507.     { gx_device *tdev = bdev->target;
  508.       return (tdev == 0 ? 0 :
  509.           (*dev_proc(tdev, draw_thin_line))(tdev, fx0, fy0, fx1, fy0,
  510.                             pdevc, lop));
  511.     }
  512. }
  513.  
  514. /* ---------------- High-level drawing ---------------- */
  515.  
  516. #define adjust_box(pbox, adj)\
  517.   ((pbox)->p.x -= (adj).x, (pbox)->p.y -= (adj).y,\
  518.    (pbox)->q.x += (adj).x, (pbox)->q.y += (adj).y)
  519.  
  520. private int
  521. bbox_fill_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  522.   const gx_fill_params *params, const gx_device_color *pdevc,
  523.   const gx_clip_path *pcpath)
  524. {    gx_device *tdev = bdev->target;
  525.  
  526.     if ( !gx_dc_is_white(pdevc, bdev) )
  527.       { gs_fixed_rect ibox;
  528.         gs_fixed_point adjust;
  529.  
  530.         if ( gx_path_bbox(ppath, &ibox) < 0 )
  531.           return 0;
  532.         adjust = params->adjust;
  533.         if ( params->fill_zero_width )
  534.           gx_adjust_if_empty(&ibox, &adjust);
  535.         adjust_box(&ibox, adjust);
  536.         if ( pcpath != NULL &&
  537.          !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
  538.                           ibox.q.x, ibox.q.y)
  539.            )
  540.           { /* Let the target do the drawing, but break down the */
  541.         /* fill path into pieces for computing the bounding box. */
  542.         bdev->target = NULL;
  543.         gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath);
  544.         bdev->target = tdev;
  545.           }
  546.         else
  547.           { /* Just use the path bounding box. */
  548.         bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x,
  549.                   ibox.q.y);
  550.           }
  551.       }
  552.     /* Skip the call if there is no target. */
  553.     return (tdev == 0 ? 0 :
  554.         (*dev_proc(tdev, fill_path))(tdev, pis, ppath, params, pdevc,
  555.                          pcpath));
  556. }
  557.  
  558. private int
  559. bbox_stroke_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  560.   const gx_stroke_params *params,
  561.   const gx_drawing_color *pdevc, const gx_clip_path *pcpath)
  562. {    gx_device *tdev = bdev->target;
  563.  
  564.     if ( !gx_dc_is_white(pdevc, bdev) )
  565.       { gs_fixed_rect ibox;
  566.         gs_fixed_point expand;
  567.  
  568.         if ( gx_path_bbox(ppath, &ibox) < 0 )
  569.           return 0;
  570.         if ( gx_stroke_path_expansion(pis, ppath, &expand) < 0 )
  571.           ibox.p.x = ibox.p.y = min_fixed, ibox.q.x = ibox.q.y = max_fixed;
  572.         else
  573.           adjust_box(&ibox, expand);
  574.         if ( pcpath != NULL &&
  575.          !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
  576.                           ibox.q.x, ibox.q.y)
  577.            )
  578.           { /* Let the target do the drawing, but break down the */
  579.         /* fill path into pieces for computing the bounding box. */
  580.         bdev->target = NULL;
  581.         gx_default_stroke_path(dev, pis, ppath, params, pdevc, pcpath);
  582.         bdev->target = tdev;
  583.           }
  584.         else
  585.           { /* Just use the path bounding box. */
  586.         bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x,
  587.                   ibox.q.y);
  588.           }
  589.       }
  590.     /* Skip the call if there is no target. */
  591.     return (tdev == 0 ? 0 :
  592.         (*dev_proc(tdev, stroke_path))(tdev, pis, ppath, params,
  593.                            pdevc, pcpath));
  594. }
  595.  
  596. private int
  597. bbox_fill_mask(gx_device *dev,
  598.   const byte *data, int dx, int raster, gx_bitmap_id id,
  599.   int x, int y, int w, int h,
  600.   const gx_drawing_color *pdcolor, int depth,
  601.   gs_logical_operation_t lop, const gx_clip_path *pcpath)
  602. {    gx_device *tdev = bdev->target;
  603.  
  604.     if ( pcpath != NULL &&
  605.          !gx_cpath_includes_rectangle(pcpath, int2fixed(x), int2fixed(y),
  606.                       int2fixed(x + w),
  607.                       int2fixed(y + h))
  608.        )
  609.       { /* Let the target do the drawing, but break down the */
  610.         /* image into pieces for computing the bounding box. */
  611.         bdev->target = NULL;
  612.         gx_default_fill_mask(dev, data, dx, raster, id, x, y, w, h,
  613.                  pdcolor, depth, lop, pcpath);
  614.         bdev->target = tdev;
  615.       }
  616.     else
  617.       { /* Just use the mask bounding box. */
  618.         bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  619.       }
  620.     /* Skip the call if there is no target. */
  621.     return (tdev == 0 ? 0 :
  622.         (*dev_proc(tdev, fill_mask))(tdev, data, dx, raster, id, x, y,
  623.                      w, h, pdcolor, depth, lop, pcpath));
  624. }
  625.  
  626. /* ------ Bitmap imaging ------ */
  627.  
  628. typedef struct bbox_image_enum_s {
  629.     gs_memory_t *memory;
  630.     gs_matrix matrix;    /* map from image space to device space */
  631.     const gx_clip_path *pcpath;
  632.     void *target_info;
  633.     int x0, x1;
  634.     int y, height;
  635. } bbox_image_enum;
  636. gs_private_st_ptrs2(st_bbox_image_enum, bbox_image_enum, "bbox_image_enum",
  637.   bbox_image_enum_enum_ptrs, bbox_image_enum_reloc_ptrs, pcpath, target_info);
  638.  
  639. private int
  640. bbox_begin_image(gx_device *dev,
  641.   const gs_imager_state *pis, const gs_image_t *pim,
  642.   gs_image_format_t format, const gs_int_rect *prect,
  643.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
  644.   gs_memory_t *memory, void **pinfo)
  645. {    int code;
  646.     gs_matrix mat;
  647.     bbox_image_enum *pbe;
  648.  
  649.     if ( (code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
  650.          (code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat)) < 0
  651.        )
  652.       return code;
  653.     pbe = gs_alloc_struct(memory, bbox_image_enum, &st_bbox_image_enum,
  654.                   "bbox_begin_image");
  655.     if ( pbe == 0 )
  656.       return_error(gs_error_VMerror);
  657.     pbe->memory = memory;
  658.     pbe->matrix = mat;
  659.     pbe->pcpath = pcpath;
  660.     pbe->target_info = 0;        /* in case no target */
  661.     if ( prect )
  662.       { pbe->x0 = prect->p.x, pbe->x1 = prect->q.x;
  663.         pbe->y = prect->p.y, pbe->height = prect->q.y - prect->p.y;
  664.       }
  665.     else
  666.       { pbe->x0 = 0, pbe->x1 = pim->Width;
  667.         pbe->y = 0, pbe->height = pim->Height;
  668.       }
  669.     *pinfo = pbe;
  670.     /* Skip the call if there is no target. */
  671.     { gx_device *tdev = bdev->target;
  672.       return (tdev == 0 ? 0 :
  673.           (*dev_proc(tdev, begin_image))(tdev, pis, pim, format, prect,
  674.                          pdcolor, pcpath, memory,
  675.                          &pbe->target_info));
  676.     }
  677. }
  678.  
  679. private int
  680. bbox_image_data(gx_device *dev,
  681.   void *info, const byte **planes, int data_x, uint raster, int height)
  682. {    gx_device *tdev = bdev->target;
  683.     bbox_image_enum *pbe = info;
  684.     const gx_clip_path *pcpath = pbe->pcpath;
  685.     gs_rect sbox, dbox;
  686.     gs_point corners[4];
  687.     gs_fixed_rect ibox;
  688.  
  689.     sbox.p.x = pbe->x0;
  690.     sbox.p.y = pbe->y;
  691.     sbox.q.x = pbe->x1;
  692.     sbox.q.y = pbe->y += height;
  693.     gs_bbox_transform_only(&sbox, &pbe->matrix, corners);
  694.     gs_points_bbox(corners, &dbox);
  695.     ibox.p.x = float2fixed(dbox.p.x);
  696.     ibox.p.y = float2fixed(dbox.p.y);
  697.     ibox.q.x = float2fixed(dbox.q.x);
  698.     ibox.q.y = float2fixed(dbox.q.y);
  699.     if ( pcpath != NULL &&
  700.          !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
  701.                       ibox.q.x, ibox.q.y)
  702.        )
  703.       { /* Let the target do the drawing, but drive two triangles */
  704.         /* through the clipping path to get an accurate bounding box. */
  705.         gx_device_clip cdev;
  706.         gx_drawing_color devc;
  707.         fixed x0 = float2fixed(corners[0].x),
  708.           y0 = float2fixed(corners[0].y);
  709.         fixed bx2 = float2fixed(corners[2].x) - x0,
  710.           by2 = float2fixed(corners[2].y) - y0;
  711.  
  712.         gx_make_clip_path_device(&cdev, pcpath);
  713.         cdev.target = dev;
  714.         (*dev_proc(&cdev, open_device))((gx_device *)&cdev);
  715.         color_set_pure(&devc, 0);        /* any color will do */
  716.         bdev->target = NULL;
  717.         gx_default_fill_triangle((gx_device *)&cdev, x0, y0,
  718.                      float2fixed(corners[1].x) - x0,
  719.                      float2fixed(corners[1].y) - y0,
  720.                      bx2, by2, &devc, lop_default);
  721.         gx_default_fill_triangle((gx_device *)&cdev, x0, y0,
  722.                      float2fixed(corners[3].x) - x0,
  723.                      float2fixed(corners[3].y) - y0,
  724.                      bx2, by2, &devc, lop_default);
  725.         bdev->target = tdev;
  726.       }
  727.     else
  728.       { /* Just use the bounding box. */
  729.         bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
  730.       }
  731.     /* Skip the call if there is no target. */
  732.     return (tdev == 0 ? pbe->y >= pbe->height :
  733.         (*dev_proc(tdev, image_data))(tdev, pbe->target_info, planes,
  734.                           data_x, raster, height));
  735. }
  736.  
  737. private int
  738. bbox_end_image(gx_device *dev, void *info, bool draw_last)
  739. {    bbox_image_enum *pbe = info;
  740.     void *target_info = pbe->target_info;
  741.     /* Skip the call if there is no target. */
  742.     gx_device *tdev = bdev->target;
  743.     int code =
  744.       (tdev == 0 ? 0 :
  745.        (*dev_proc(tdev, end_image))(tdev, target_info, draw_last));
  746.  
  747.     gs_free_object(pbe->memory, pbe, "bbox_end_image");
  748.     return code;
  749. }
  750.